package com.generate.service;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.generate.param.GenerateParam;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 代码生成
 * @author ytj
 * @date 2021/6/7
 */
@Service
public class CodeGeneratorService {

    public void codeGenerator(GenerateParam generateParam){
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        //获取程序当前地址
        String projectPath = System.getProperty("user.dir");
        //全局配置
        mpg.setGlobalConfig(this.getGlobalConfig(generateParam.getAuthor(),projectPath));
        //数据库配置
        mpg.setDataSource(this.getDataSourceConfig(generateParam.getPath(),generateParam.getData(),generateParam.getUser(),generateParam.getPassword()));
        // 包配置
        mpg.setPackageInfo(this.getPackageConfig(generateParam.getName(),generateParam.getParent()));
        //自定义配置
        mpg.setCfg(this.getInjectionConfig(projectPath,generateParam.getName()));
        // 配置模板
        mpg.setTemplate(this.getTemplateConfig());
        // 策略配置
        mpg.setStrategy(this.getStrategyConfig(generateParam.getTableName(),generateParam.getName()));
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
    /**
     * 获取全局配置
     * @param author 作者
     * @param projectPath 项目路径
     * */
    private GlobalConfig getGlobalConfig(String author, String projectPath){
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(projectPath);
        //设置作者
        gc.setAuthor(author);
        gc.setOpen(false);
        // gc.setSwagger2(true); 实体属性 Swagger2 注解
        return gc;
    }

    /**
     * 获取数据源配置
     * @param path 路径
     * @param data 数据库
     * @param user 用户名
     * @param password 密码
     * */
    private DataSourceConfig getDataSourceConfig(String path, String data,
                                                 String user, String password){
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        String url="jdbc:mysql://"+path+":3306/"+data+"?useUnicode=true&useSSL=false&characterEncoding=utf8";
        dsc.setUrl(url);
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername(user);
        dsc.setPassword(password);
        return dsc;
    }

    /**
     * 包配置
     * @param name 模块名称
     * @param parent 模块父类名称
     * */
    private PackageConfig getPackageConfig(String name, String parent){
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(name);
        pc.setParent(parent);
        return pc;
    }

    /**
     * 获取自定义配置
     * */
    private InjectionConfig getInjectionConfig(String projectPath, String name){
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";
        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                return projectPath + "/mapper/" + name
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        return cfg;
    }

    /**
     * 配置模板
     * */
    private TemplateConfig getTemplateConfig(){
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null);
        return templateConfig;
    }

    /**
     * 策略配置
     * */
    private StrategyConfig getStrategyConfig(String tableName,String name){
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//        strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        // 公共父类
//        strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("id");
        strategy.setInclude(tableName);
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(name + "_");
        return strategy;
    }

    /**
     * 文件压缩
     * */
    private String zipFile(String parent){
        //获取程序当前地址
        String projectPath = System.getProperty("user.dir");
        String path="";
        if(parent.contains(".")){
            String[] array=parent.split("\\.");
            path=array[0];
        }else{
            path=parent;
        }
        //将生成的文件全部压缩
        path=projectPath+"\\"+path;
        ZipUtil.zip(path);
        //将生成的文件删除
        FileUtil.del(path);
        return path+".zip";
    }


    public HttpServletResponse download(String parent, HttpServletResponse response) {
        String path="";
        try {
            path=this.zipFile(parent);
            // path是指欲下载的文件的路径。
            File file = new File(path);
            // 取得文件名。
            String filename = file.getName();

            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
            response.addHeader("Content-Length", "" + file.length());
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }finally {
            FileUtil.del(path);
        }
        return response;
    }



}
